use crate::dto;
use crate::service::Error;
use crate::service::candidate_path_segment_list::CandidatePathSegmentListService;
use crate::service::segment_list_manager::SegmentListManagerService;
use std::sync::Arc;

#[async_trait::async_trait]
pub trait CandidatePathSegmentListManagerService: CandidatePathSegmentListService {
    async fn all_info(
        &self,
        candidate_path_id: &str,
    ) -> Result<Vec<dto::candidate_path_segment_list::CandidatePathSegmentListInfo>, Error>;
}

pub struct DefaultCandidatePathSegmentListManagerService {
    candidate_path_segment_list_service: Arc<dyn CandidatePathSegmentListService>,
    segment_list_manager: Arc<dyn SegmentListManagerService>,
}

impl DefaultCandidatePathSegmentListManagerService {
    pub fn new(
        candidate_path_segment_list_service: Arc<dyn CandidatePathSegmentListService>,
        segment_list_manager: Arc<dyn SegmentListManagerService>,
    ) -> Self {
        DefaultCandidatePathSegmentListManagerService {
            candidate_path_segment_list_service,
            segment_list_manager,
        }
    }

    async fn get_info_by_core(
        &self,
        candidate_path_segment_list: dto::core::candidate_path_segment_list::CandidatePathSegmentList,
    ) -> Result<dto::candidate_path_segment_list::CandidatePathSegmentListInfo, Error> {
        let segment_list = self
            .segment_list_manager
            .get_info(candidate_path_segment_list.segment_list_id.as_str())
            .await?;

        Ok(
            dto::candidate_path_segment_list::CandidatePathSegmentListInfo {
                inner: candidate_path_segment_list,
                endpoint_id_list: segment_list.endpoint_id_list,
            },
        )
    }
}

#[async_trait::async_trait]
impl CandidatePathSegmentListService for DefaultCandidatePathSegmentListManagerService {
    async fn add(
        &self,
        params: &dto::core::candidate_path_segment_list::AddParams,
    ) -> Result<(), Error> {
        self.candidate_path_segment_list_service.add(params).await
    }

    async fn list(
        &self,
        filter: &dto::core::candidate_path_segment_list::Filter,
        offset: u64,
        limit: u64,
    ) -> Result<Vec<dto::core::candidate_path_segment_list::CandidatePathSegmentList>, Error> {
        self.candidate_path_segment_list_service
            .list(filter, offset, limit)
            .await
    }

    async fn all(
        &self,
        candidate_path_id: &str,
    ) -> Result<Vec<dto::core::candidate_path_segment_list::CandidatePathSegmentList>, Error> {
        self.candidate_path_segment_list_service.all(candidate_path_id).await
    }

    async fn delete_by_filter(
        &self,
        filter: &dto::core::candidate_path_segment_list::Filter,
    ) -> Result<(), Error> {
        self.candidate_path_segment_list_service
            .delete_by_filter(filter)
            .await
    }
}

#[async_trait::async_trait]
impl CandidatePathSegmentListManagerService for DefaultCandidatePathSegmentListManagerService {
    async fn all_info(
        &self,
        candidate_path_id: &str,
    ) -> Result<Vec<dto::candidate_path_segment_list::CandidatePathSegmentListInfo>, Error> {
        let candidate_path_segment_lists = self.all(candidate_path_id).await?;

        let mut list = Vec::new();
        for candidate_path_segment_list in candidate_path_segment_lists {
            let info = self.get_info_by_core(candidate_path_segment_list).await?;
            list.push(info);
        }

        Ok(list)
    }
}
